package main

import (
	"fengxueguang/novel-assistan/core"
	"fengxueguang/novel-assistan/log"
	"fengxueguang/novel-assistan/utils"
	"flag"
	"fmt"
	"github.com/fvbock/endless"
	"github.com/gin-gonic/gin"
	"os"

	"fengxueguang/novel-assistan/common"
	"fengxueguang/novel-assistan/middleware"
	"fengxueguang/novel-assistan/route"
	//"os"
	//"os/signal"
	"github.com/google/uuid"
	"runtime"
	"syscall"
)

func main() {
	// 启动多核调度
	runtime.GOMAXPROCS(runtime.NumCPU())
	// 创建一个通道来接收操作系统信号
	//sigChan := make(chan os.Signal, 1)
	//signal.Notify(sigChan, syscall.SIGHUP)
	uuidStr := uuid.New().String()
	// 读取命令行参数，初始化配置
	var configPath string
	flag.StringVar(&configPath, "config", "conf/service.conf", "server config")
	flag.Parse()
	common.InitConfig(configPath)

	cfg := common.GetConfig()
	// init fish  zap log(uber)
	log.InitLog(cfg)

	core.RegisterPlugs(cfg)

	gin.SetMode(cfg.Server.GinMode)
	log.SwitchSkip2(cfg)

	// http服务
	r := gin.New()

	// 中间件  日志、错误处理
	//r.Use(middleware.LoggerMiddleware())
	r.Use(middleware.AddTraceId())
	r.Use(middleware.ZapLoggerMiddleware()) // 日志同时增加响应头信息
	r.Use(middleware.ErrorHandler())
	r.Use(middleware.TimeoutMiddleware())

	// 设置路由 get and post
	route.SetGetRoute(r)

	//err := r.Run(fmt.Sprintf(":%d", cfg.Server.Port)) // listen and serve on
	//if err != nil {
	//	log.Fatalf("listen: %s\n", err)
	//}

	// 使用 endless 替代 Gin 的默认服务器启动
	//endless.DefaultReadTimeOut = 5 * time.Second  // 设置读取超时时间
	//endless.DefaultWriteTimeOut = 5 * time.Second // 设置写入超时时间
	//endless.DefaultMaxHeaderBytes = 1 << 20       // 设置最大请求头大小
	//var waitShutdown = make(chan struct{})
	// 在main函数中的server.RegisterOnShutdown函数中增加等待通道

	// 新服务器启动前，等待所有连接关闭
	//<-waitShutdown

	// 用gin自带的
	//srv := &http.Server{
	//	Addr:    fmt.Sprintf(":%d", cfg.Server.Port),
	//	Handler: r,
	//}
	//go func() {
	//	// 开启一个goroutine启动服务
	//	if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
	//		log.Fatalf("listen: %s\n", err)
	//	}
	//}()
	//
	//// 等待中断信号来优雅地关闭服务器，为关闭服务器操作设置一个5秒的超时
	//quit := make(chan os.Signal, 1) // 创建一个接收信号的通道
	//// kill 默认会发送 syscall.SIGTERM 信号
	//// kill -2 发送 syscall.SIGINT 信号，我们常用的Ctrl+C就是触发系统SIGINT信号
	//// kill -9 发送 syscall.SIGKILL 信号，但是不能被捕获，所以不需要添加它
	//// signal.Notify把收到的 syscall.SIGINT或syscall.SIGTERM 信号转发给quit
	//signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) // 此处不会阻塞
	//<-quit                                               // 阻塞在此，当接收到上述两种信号时才会往下执行
	//log.Info("Shutdown Server ...")
	//// 创建一个5秒超时的context
	//ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	//defer cancel()
	//defer func() {
	//	core.UnRegisterPlugs()
	//}()
	//// 5秒内优雅关闭服务（将未处理完的请求处理完再关闭服务），超过5秒就超时退出
	//if err := srv.Shutdown(ctx); err != nil {
	//	log.Fatal("Server Shutdown: ", err)
	//}
	pid := 0
	server := endless.NewServer(fmt.Sprintf(":%d", cfg.Server.Port), r)
	server.BeforeBegin = func(add string) {
		log.SwitchSkip1(cfg)
		pid = syscall.Getpid()
		updatePidFile(cfg.Server.PidFile, pid)
		log.Printf("uuid:%s Actual pid is %d", uuidStr, pid)
		log.SwitchSkip2(cfg)
		//client.UnRegisterPlugs()
	}
	server.RegisterOnShutdown(func() {
		log.Infof("pid:%d uuid:%s Server on shutdown", pid, uuidStr)
		core.UnRegisterPlugs(uuidStr + " RegisterOnShutdown")
		// 等待所有连接关闭
		// 这里假设有一个名为"waitShutdown"的通道
		//waitShutdown <- struct{}{}
	})

	defer func() {
		core.UnRegisterPlugs(uuidStr + "defer")
	}()

	// 启动服务器
	err := server.ListenAndServe()
	if err != nil {
		log.SwitchSkip1(cfg)
		core.UnRegisterPlugs(uuidStr + " server.ListenAndServe err")
		log.Errorf("pid:%d uuid:%s %v", pid, uuidStr, err)
	}

	if err = endless.ListenAndServe(fmt.Sprintf(":%d", cfg.Server.Port), r); err != nil {
		log.SwitchSkip1(cfg)
		log.Fatalf("pid:%d uuid:%s listen: %s\n", pid, uuidStr, err)
	}
}

func updatePidFile(filePath string, pid int) {
	// 创建pid文件
	pidFile, err := os.Create(filePath)
	if err != nil {
		log.Error(err)
		return
	}

	defer func() {
		err = pidFile.Close()
		if err != nil {
			log.Error(err)
		}
	}()

	// 写入文件内容
	str := fmt.Sprintf("%d", pid)
	_, err = pidFile.WriteString(str)
	if err != nil {
		log.Error(err)
	}

	pidFile2, err := os.OpenFile(filePath+".append", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		log.Error(err)
		return
	}

	defer func() {
		err = pidFile2.Close()
		if err != nil {
			log.Error(err)
		}
	}()

	// 写入文件内容
	_, err = pidFile2.WriteString(str + " " + utils.NowTime() + "\n")
	if err != nil {
		log.Error(err)
	}
}
